package com.sakiko.rag.controller;

import com.sakiko.rag.service.ChatAssistant;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.document.parser.apache.tika.ApacheTikaDocumentParser;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

/**
 * projectName: com.sakiko.rag.controller
 *
 * @author: sakiko
 * time: 2025/8/30 17:46
 * description: https://docs.langchain4j.dev/tutorials/rag#core-rag-apis
 * 上述核心 api主要内容；
 * EmbeddingStoreIngestor 组织结构分析
 * Document Loader 文档加载器
 * Document Parser 文档解析器
 * Document Transformer 文档转换器
 * Document Splitter 文档拆分器
 */
@RestController
@Slf4j
public class RAGController {

    @Resource
//    EmbeddingStore<TextSegment> embeddingStore; // Qdrant
    InMemoryEmbeddingStore<TextSegment> inMemoryEmbeddingStore; // InMemory
    @Resource
    ChatAssistant chatAssistant;

    // http://localhost:9013/rag/add
    @GetMapping("/rag/add")
    public String testAdd() throws FileNotFoundException {
//        Document document = FileSystemDocumentLoader.loadDocument("D:\\阿里Java开发手册黄山版2022.02.03V1.7.1.pdf");
        FileInputStream fileInputStream = new FileInputStream("D:\\阿里Java开发手册黄山版2022.02.03V1.7.1.pdf");
        Document document = new ApacheTikaDocumentParser().parse(fileInputStream);

        EmbeddingStoreIngestor.ingest(document, inMemoryEmbeddingStore);
        String res = chatAssistant.chat("错误码00000和A0001分别是什么");

        System.out.println("res = " + res);
        return res;
    }

}

/*
构建 RAG的一般步骤:
    1、加载文档: 使用适当的【DocumentLoader】和【DocumentParser】加载文档
    2、转换文档: 使用【DocumentTransformer】清理或增强文档
    3、拆分文档: 使用【DocumentSplitter】将文档拆分为更小的片段
    4、嵌入文档: 使用【EmbeddingModel】将文档片段转换为嵌入向量
    5、存储嵌入: 使用 【EmbeddingStoreIngestor】存储嵌入向量
    6、检索相关内容: 根据用户查询，从 【EmbeddingStore】检索最相关的文档片段
    7、生成响应: 将检索到的相关内容和用户查询一起提供给语言模型，生成最终响应
 */
